package cn.smalltool.core.date;

import cn.smalltool.core.lang.Assert;
import cn.smalltool.core.utils.ObjectUtil;
import cn.smalltool.core.utils.StrUtil;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

public class DateTime extends Date{

    private static final long serialVersionUID = -5395712593979185936L;
    private boolean mutable;
    private Week firstDayOfWeek;
    private TimeZone timeZone;

    public DateTime() {
        this(TimeZone.getDefault());
    }

    public DateTime(TimeZone timeZone) {
        this(System.currentTimeMillis(), timeZone);
    }

    public DateTime(Date date, TimeZone timeZone) {
        this(date.getTime(), timeZone);
    }

    public DateTime(long timeMillis, TimeZone timeZone) {
        super(timeMillis);
        this.mutable = true;
        this.firstDayOfWeek = Week.MONDAY;
        this.timeZone = (TimeZone) ObjectUtil.defaultIfNull(timeZone, TimeZone.getDefault());
    }

    public DateTime(CharSequence dateStr, String format) {
        this((CharSequence)dateStr, (DateFormat)(new SimpleDateFormat(format)));
    }

    public DateTime(CharSequence dateStr, DateFormat dateFormat) {
        this(parse(dateStr, dateFormat), dateFormat.getTimeZone());
    }

    public DateTime(Date date) {
        this(date.getTime(), date instanceof DateTime ? ((DateTime)date).timeZone : TimeZone.getDefault());
    }

    public static DateTime of(Date date) {
        return date instanceof DateTime ? (DateTime)date : new DateTime(date);
    }

    public int year() {
        return this.getField(DateField.YEAR);
    }

    public int getField(DateField field) {
        return this.getField(field.getValue());
    }

    public int getField(int field) {
        return this.toCalendar().get(field);
    }

    public Calendar toCalendar() {
        return this.toCalendar(Locale.getDefault(Locale.Category.FORMAT));
    }

    public Calendar toCalendar(Locale locale) {
        return this.toCalendar(this.timeZone, locale);
    }

    public Calendar toCalendar(TimeZone zone, Locale locale) {
        if (null == locale) {
            locale = Locale.getDefault(Locale.Category.FORMAT);
        }

        Calendar cal = null != zone ? Calendar.getInstance(zone, locale) : Calendar.getInstance(locale);
        cal.setFirstDayOfWeek(this.firstDayOfWeek.getValue());
        cal.setTime(this);
        return cal;
    }

    private static Date parse(CharSequence dateStr, DateFormat dateFormat) {
        Assert.notBlank(dateStr, "Date String must be not blank !", new Object[0]);

        try {
            return dateFormat.parse(dateStr.toString());
        } catch (Exception var4) {
            String pattern;
            if (dateFormat instanceof SimpleDateFormat) {
                pattern = ((SimpleDateFormat)dateFormat).toPattern();
            } else {
                pattern = dateFormat.toString();
            }

            throw new DateException(StrUtil.format("Parse [{}] with format [{}] error!", new Object[]{dateStr, pattern}), var4);
        }
    }
}
